/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "driver/ioc/hpm6e00_ioc.h"

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief IO 控制器功能设置
 *
 * \param[in] pad_num 引脚编号
 * \param[in] func    具体功能
 *
 * \retval 成功返回 0
 */
int ioc_pad_func_set(uint32_t pad_num, uint32_t func){
    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    WRITE_REG32(HPM_IOC->pad[pad_num].FUNC_CTL, func);

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        WRITE_REG32(HPM_PIOC->pad[pad_num].FUNC_CTL, 3);
    }

    if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        WRITE_REG32(HPM_BIOC->pad[pad_num].FUNC_CTL, 3);
    }

    return 0;
}

/**
 * \brief IO 控制器配置设置
 *
 * \param[in] pad_num  引脚编号
 * \param[in] pad_ctrl 具体配置
 *
 * \retval 成功返回 0
 */
int ioc_pad_ctrl_set(uint32_t pad_num, uint32_t pad_ctrl){
    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    WRITE_REG32(HPM_IOC->pad[pad_num].PAD_CTL, pad_ctrl);

    return 0;
}

/**
 * \brief 设置 GPIO 引脚为输入
 *
 * \param[in] pad_num 引脚编号
 *
 * \retval 成功返回 0
 */
int ioc_pad_gpio_input_set(uint32_t pad_num){
    uint32_t port, pin;

    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    port = pad_num / 32;
    pin  = pad_num % 32;

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        WRITE_REG32(HPM_PGPIO->OE[port].CLEAR, 1 << pin);
    } else if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        WRITE_REG32(HPM_BGPIO->OE[port].CLEAR, 1 << pin);
    } else {
        WRITE_REG32(HPM_GPIO0->OE[port].CLEAR, 1 << pin);
    }
    return 0;
}

/**
 * \brief 设置 GPIO 引脚为输出
 *
 * \param[in] pad_num 引脚编号
 *
 * \retval 成功返回 0
 */
int ioc_pad_gpio_output_set(uint32_t pad_num){
    uint32_t port, pin;

    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    port = pad_num / 32;
    pin  = pad_num % 32;

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        WRITE_REG32(HPM_PGPIO->OE[port].SET, 1 << pin);
    } else if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        WRITE_REG32(HPM_BGPIO->OE[port].SET, 1 << pin);
    } else {
        WRITE_REG32(HPM_GPIO0->OE[port].SET, 1 << pin);
    }

    return 0;
}

/**
 * \brief 读取 GPIO 引脚电平状态
 *
 * \param[in] pad_num  引脚编号
 *
 * \retval 返回 1 表示高电平，0 表示低电平，负数表示错误
 */
int ioc_pad_gpio_sta_get(uint32_t pad_num){
    uint32_t port, pin;

    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    port = pad_num / 32;
    pin  = pad_num % 32;

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        return (HPM_PGPIO->DI[port].VALUE & (1 << pin)) >> pin;
    } else if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        return (HPM_BGPIO->DI[port].VALUE & (1 << pin)) >> pin;
    }

    return (HPM_GPIO0->DI[port].VALUE & (1 << pin)) >> pin;
}

/**
 * \brief 读取 GPIO 引脚电平状态
 *
 * \param[in] pad_num 引脚编号
 * \param[in] val     引脚电平值
 *
 * \retval 成功返回 0
 */
int ioc_pad_gpio_sta_set(uint32_t pad_num, uint8_t val){
    uint32_t         port, pin;
    hpm_gpio_regs_t *p_gpio_reg = NULL;

    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    port = pad_num / 32;
    pin  = pad_num % 32;

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        p_gpio_reg = HPM_PGPIO;
    } else if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        p_gpio_reg = HPM_BGPIO;
    } else {
        p_gpio_reg = HPM_GPIO0;
    }

    if (val == 1) {
        WRITE_REG32(p_gpio_reg->DO[port].SET, 1 << pin);
    } else {
        WRITE_REG32(p_gpio_reg->DO[port].CLEAR, 1 << pin);
    }

    return 0;
}

/**
 * \brief 翻转 GPIO 引脚电平状态
 *
 * \param[in] pad_num 引脚编号
 *
 * \retval 成功返回 0
 */
int ioc_pad_gpio_sta_toggle(uint32_t pad_num){
    uint32_t port, pin;

    if (pad_num > IOC_PAD_PZ07) {
        return -EINVAL;
    }

    port = pad_num / 32;
    pin  = pad_num % 32;

    if ((pad_num >= IOC_PAD_PY00) && (pad_num <= IOC_PAD_PY07)) {
        WRITE_REG32(HPM_PGPIO->DO[port].TOGGLE, 1 << pin);
    } else if ((pad_num >= IOC_PAD_PZ00) && (pad_num <= IOC_PAD_PZ07)) {
        WRITE_REG32(HPM_BGPIO->DO[port].TOGGLE, 1 << pin);
    } else {
        WRITE_REG32(HPM_GPIO0->DO[port].TOGGLE, 1 << pin);
    }

    return 0;
}
